/****************************************************************************
 *
 * Copyright 2016 Samsung Electronics All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 *
 ****************************************************************************/
/**
 * \file ssl_ticket.h
 *
 * \brief Internal functions shared by the SSL modules
 *
 *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This file is part of mbed TLS (https://tls.mbed.org)
 */
#ifndef MBEDTLS_SSL_INTERNAL_H
#define MBEDTLS_SSL_INTERNAL_H

#include "ssl.h"

#if defined(MBEDTLS_MD5_C)
#include "md5.h"
#endif

#if defined(MBEDTLS_SHA1_C)
#include "sha1.h"
#endif

#if defined(MBEDTLS_SHA256_C)
#include "sha256.h"
#endif

#if defined(MBEDTLS_SHA512_C)
#include "sha512.h"
#endif

#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
#include "ecjpake.h"
#endif

#if (defined(__ARMCC_VERSION) || defined(_MSC_VER)) && \
	!defined(inline) && !defined(__cplusplus)
#define inline __inline
#endif

/* Determine minimum supported version */
#define MBEDTLS_SSL_MIN_MAJOR_VERSION           MBEDTLS_SSL_MAJOR_VERSION_3

#if defined(MBEDTLS_SSL_PROTO_SSL3)
#define MBEDTLS_SSL_MIN_MINOR_VERSION           MBEDTLS_SSL_MINOR_VERSION_0
#else
#if defined(MBEDTLS_SSL_PROTO_TLS1)
#define MBEDTLS_SSL_MIN_MINOR_VERSION           MBEDTLS_SSL_MINOR_VERSION_1
#else
#if defined(MBEDTLS_SSL_PROTO_TLS1_1)
#define MBEDTLS_SSL_MIN_MINOR_VERSION           MBEDTLS_SSL_MINOR_VERSION_2
#else
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#define MBEDTLS_SSL_MIN_MINOR_VERSION           MBEDTLS_SSL_MINOR_VERSION_3
#endif							/* MBEDTLS_SSL_PROTO_TLS1_2 */
#endif							/* MBEDTLS_SSL_PROTO_TLS1_1 */
#endif							/* MBEDTLS_SSL_PROTO_TLS1   */
#endif							/* MBEDTLS_SSL_PROTO_SSL3   */

/* Determine maximum supported version */
#define MBEDTLS_SSL_MAX_MAJOR_VERSION           MBEDTLS_SSL_MAJOR_VERSION_3

#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#define MBEDTLS_SSL_MAX_MINOR_VERSION           MBEDTLS_SSL_MINOR_VERSION_3
#else
#if defined(MBEDTLS_SSL_PROTO_TLS1_1)
#define MBEDTLS_SSL_MAX_MINOR_VERSION           MBEDTLS_SSL_MINOR_VERSION_2
#else
#if defined(MBEDTLS_SSL_PROTO_TLS1)
#define MBEDTLS_SSL_MAX_MINOR_VERSION           MBEDTLS_SSL_MINOR_VERSION_1
#else
#if defined(MBEDTLS_SSL_PROTO_SSL3)
#define MBEDTLS_SSL_MAX_MINOR_VERSION           MBEDTLS_SSL_MINOR_VERSION_0
#endif							/* MBEDTLS_SSL_PROTO_SSL3   */
#endif							/* MBEDTLS_SSL_PROTO_TLS1   */
#endif							/* MBEDTLS_SSL_PROTO_TLS1_1 */
#endif							/* MBEDTLS_SSL_PROTO_TLS1_2 */

#define MBEDTLS_SSL_INITIAL_HANDSHAKE           0
#define MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS   1	/* In progress */
#define MBEDTLS_SSL_RENEGOTIATION_DONE          2	/* Done or aborted */
#define MBEDTLS_SSL_RENEGOTIATION_PENDING       3	/* Requested (server only) */

/*
 * DTLS retransmission states, see RFC 6347 4.2.4
 *
 * The SENDING state is merged in PREPARING for initial sends,
 * but is distinct for resends.
 *
 * Note: initial state is wrong for server, but is not used anyway.
 */
#define MBEDTLS_SSL_RETRANS_PREPARING       0
#define MBEDTLS_SSL_RETRANS_SENDING         1
#define MBEDTLS_SSL_RETRANS_WAITING         2
#define MBEDTLS_SSL_RETRANS_FINISHED        3

/*
 * Allow extra bytes for record, authentication and encryption overhead:
 * counter (8) + header (5) + IV(16) + MAC (16-48) + padding (0-256)
 * and allow for a maximum of 1024 of compression expansion if
 * enabled.
 */
#if defined(MBEDTLS_ZLIB_SUPPORT)
#define MBEDTLS_SSL_COMPRESSION_ADD          1024
#else
#define MBEDTLS_SSL_COMPRESSION_ADD             0
#endif

#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_MODE_CBC)
/* Ciphersuites using HMAC */
#if defined(MBEDTLS_SHA512_C)
#define MBEDTLS_SSL_MAC_ADD                 48	/* SHA-384 used for HMAC */
#elif defined(MBEDTLS_SHA256_C)
#define MBEDTLS_SSL_MAC_ADD                 32	/* SHA-256 used for HMAC */
#else
#define MBEDTLS_SSL_MAC_ADD                 20	/* SHA-1   used for HMAC */
#endif
#else
/* AEAD ciphersuites: GCM and CCM use a 128 bits tag */
#define MBEDTLS_SSL_MAC_ADD                 16
#endif

#if defined(MBEDTLS_CIPHER_MODE_CBC)
#define MBEDTLS_SSL_PADDING_ADD            256
#else
#define MBEDTLS_SSL_PADDING_ADD              0
#endif

#define MBEDTLS_SSL_BUFFER_LEN  (MBEDTLS_SSL_MAX_CONTENT_LEN           \
								+ MBEDTLS_SSL_COMPRESSION_ADD          \
								+ 29 /* counter + header + IV */       \
								+ MBEDTLS_SSL_MAC_ADD                  \
								+ MBEDTLS_SSL_PADDING_ADD)

/*
 * TLS extension flags (for extensions with outgoing ServerHello content
 * that need it (e.g. for RENEGOTIATION_INFO the server already knows because
 * of state of the renegotiation flag, so no indicator is required)
 */
#define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT (1 << 0)
#define MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK                 (1 << 1)

#ifdef __cplusplus
extern "C" {
#endif

/*
 * This structure contains the parameters only needed during handshake.
 */
struct mbedtls_ssl_handshake_params {
	/*
	 * Handshake specific crypto variables
	 */
	int sig_alg;			/*!<  Hash algorithm for signature   */
	int verify_sig_alg;		/*!<  Signature algorithm for verify */
#if defined(MBEDTLS_DHM_C)
	mbedtls_dhm_context dhm_ctx;	/*!<  DHM key exchange        */
#endif
#if defined(MBEDTLS_ECDH_C)
	mbedtls_ecdh_context ecdh_ctx;	/*!<  ECDH key exchange       */
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
	mbedtls_ecjpake_context ecjpake_ctx;	/*!< EC J-PAKE key exchange */
#if defined(MBEDTLS_SSL_CLI_C)
	unsigned char *ecjpake_cache;	/*!< Cache for ClientHello ext */
	size_t ecjpake_cache_len;	/*!< Length of cached data */
#endif
#endif
#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
	defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
	const mbedtls_ecp_curve_info **curves;	/*!<  Supported elliptic curves */
#endif
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
	unsigned char *psk;		/*!<  PSK from the callback         */
	size_t psk_len;			/*!<  Length of PSK from callback   */
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C)
	mbedtls_ssl_key_cert *key_cert;	/*!< chosen key/cert pair (server)  */
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
	int sni_authmode;		/*!< authmode from SNI callback     */
	mbedtls_ssl_key_cert *sni_key_cert;	/*!< key/cert list from SNI         */
	mbedtls_x509_crt *sni_ca_chain;	/*!< trusted CAs from SNI callback  */
	mbedtls_x509_crl *sni_ca_crl;	/*!< trusted CAs CRLs from SNI      */
#endif
#endif							/* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
	unsigned int out_msg_seq;	/*!<  Outgoing handshake sequence number */
	unsigned int in_msg_seq;	/*!<  Incoming handshake sequence number */

	unsigned char *verify_cookie;	/*!<  Cli: HelloVerifyRequest cookie
										   Srv: unused                    */
	unsigned char verify_cookie_len;	/*!<  Cli: cookie length
											   Srv: flag for sending a cookie */

	unsigned char *hs_msg;	/*!<  Reassembled handshake message  */

	uint32_t retransmit_timeout;	/*!<  Current value of timeout       */
	unsigned char retransmit_state;	/*!<  Retransmission state           */
	mbedtls_ssl_flight_item *flight;	/*!<  Current outgoing flight        */
	mbedtls_ssl_flight_item *cur_msg;	/*!<  Current message in flight      */
	unsigned int in_flight_start_seq;	/*!<  Minimum message sequence in the
											   flight being received          */
	mbedtls_ssl_transform *alt_transform_out;	/*!<  Alternative transform for
													   resending messages             */
	unsigned char alt_out_ctr[8];	/*!<  Alternative record epoch/counter
										   for resending messages         */
#endif

	/*
	 * Checksum contexts
	 */
#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
	defined(MBEDTLS_SSL_PROTO_TLS1_1)
	mbedtls_md5_context fin_md5;
	mbedtls_sha1_context fin_sha1;
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
	mbedtls_sha256_context fin_sha256;
#endif
#if defined(MBEDTLS_SHA512_C)
	mbedtls_sha512_context fin_sha512;
#endif
#endif							/* MBEDTLS_SSL_PROTO_TLS1_2 */

	void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t);
	void (*calc_verify)(mbedtls_ssl_context *, unsigned char *);
	void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int);
	int (*tls_prf)(const unsigned char *, size_t, const char *, const unsigned char *, size_t, unsigned char *, size_t);

	size_t pmslen;			/*!<  premaster length        */

	unsigned char randbytes[64];	/*!<  random bytes            */
	unsigned char premaster[MBEDTLS_PREMASTER_SIZE];
	/*!<  premaster secret        */

	int resume;				/*!<  session resume indicator */
	int max_major_ver;		/*!< max. major version client */
	int max_minor_ver;		/*!< max. minor version client */
	int cli_exts;			/*!< client extension presence */

#if defined(MBEDTLS_SSL_SESSION_TICKETS)
	int new_session_ticket;	/*!< use NewSessionTicket?    */
#endif							/* MBEDTLS_SSL_SESSION_TICKETS */
#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
	int extended_ms;		/*!< use Extended Master Secret? */
#endif
};

/*
 * This structure contains a full set of runtime transform parameters
 * either in negotiation or active.
 */
struct mbedtls_ssl_transform {
	/*
	 * Session specific crypto layer
	 */
	const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
	/*!<  Chosen cipersuite_info  */
	unsigned int keylen;	/*!<  symmetric key length (bytes)  */
	size_t minlen;			/*!<  min. ciphertext length  */
	size_t ivlen;			/*!<  IV length               */
	size_t fixed_ivlen;		/*!<  Fixed part of IV (AEAD) */
	size_t maclen;			/*!<  MAC length              */

	unsigned char iv_enc[16];	/*!<  IV (encryption)         */
	unsigned char iv_dec[16];	/*!<  IV (decryption)         */

#if defined(MBEDTLS_SSL_PROTO_SSL3)
	/* Needed only for SSL v3.0 secret */
	unsigned char mac_enc[20];	/*!<  SSL v3.0 secret (enc)   */
	unsigned char mac_dec[20];	/*!<  SSL v3.0 secret (dec)   */
#endif							/* MBEDTLS_SSL_PROTO_SSL3 */

	mbedtls_md_context_t md_ctx_enc;	/*!<  MAC (encryption)        */
	mbedtls_md_context_t md_ctx_dec;	/*!<  MAC (decryption)        */

	mbedtls_cipher_context_t cipher_ctx_enc;	/*!<  encryption context      */
	mbedtls_cipher_context_t cipher_ctx_dec;	/*!<  decryption context      */

	/*
	 * Session specific compression layer
	 */
#if defined(MBEDTLS_ZLIB_SUPPORT)
	z_stream ctx_deflate;	/*!<  compression context     */
	z_stream ctx_inflate;	/*!<  decompression context   */
#endif
};

#if defined(MBEDTLS_X509_CRT_PARSE_C)
/*
 * List of certificate + private key pairs
 */
struct mbedtls_ssl_key_cert {
	mbedtls_x509_crt *cert;	/*!< cert                       */
	mbedtls_pk_context *key;	/*!< private key                */
	mbedtls_ssl_key_cert *next;	/*!< next key/cert pair         */
};
#endif							/* MBEDTLS_X509_CRT_PARSE_C */

#if defined(MBEDTLS_SSL_PROTO_DTLS)
/*
 * List of handshake messages kept around for resending
 */
struct mbedtls_ssl_flight_item {
	unsigned char *p;		/*!< message, including handshake headers   */
	size_t len;				/*!< length of p                            */
	unsigned char type;		/*!< type of the message: handshake or CCS  */
	mbedtls_ssl_flight_item *next;	/*!< next handshake message(s)              */
};
#endif							/* MBEDTLS_SSL_PROTO_DTLS */

/**
 * \brief           Free referenced items in an SSL transform context and clear
 *                  memory
 *
 * \param transform SSL transform context
 */
void mbedtls_ssl_transform_free(mbedtls_ssl_transform *transform);

/**
 * \brief           Free referenced items in an SSL handshake context and clear
 *                  memory
 *
 * \param handshake SSL handshake context
 */
void mbedtls_ssl_handshake_free(mbedtls_ssl_handshake_params *handshake);

int mbedtls_ssl_handshake_client_step(mbedtls_ssl_context *ssl);
int mbedtls_ssl_handshake_server_step(mbedtls_ssl_context *ssl);
void mbedtls_ssl_handshake_wrapup(mbedtls_ssl_context *ssl);

int mbedtls_ssl_send_fatal_handshake_failure(mbedtls_ssl_context *ssl);

void mbedtls_ssl_reset_checksum(mbedtls_ssl_context *ssl);
int mbedtls_ssl_derive_keys(mbedtls_ssl_context *ssl);

int mbedtls_ssl_read_record_layer(mbedtls_ssl_context *ssl);
int mbedtls_ssl_handle_message_type(mbedtls_ssl_context *ssl);
int mbedtls_ssl_prepare_handshake_record(mbedtls_ssl_context *ssl);
void mbedtls_ssl_update_handshake_status(mbedtls_ssl_context *ssl);

int mbedtls_ssl_read_record(mbedtls_ssl_context *ssl);
int mbedtls_ssl_fetch_input(mbedtls_ssl_context *ssl, size_t nb_want);

int mbedtls_ssl_write_record(mbedtls_ssl_context *ssl);
int mbedtls_ssl_flush_output(mbedtls_ssl_context *ssl);

int mbedtls_ssl_parse_certificate(mbedtls_ssl_context *ssl);
int mbedtls_ssl_write_certificate(mbedtls_ssl_context *ssl);

int mbedtls_ssl_parse_change_cipher_spec(mbedtls_ssl_context *ssl);
int mbedtls_ssl_write_change_cipher_spec(mbedtls_ssl_context *ssl);

int mbedtls_ssl_parse_finished(mbedtls_ssl_context *ssl);
int mbedtls_ssl_write_finished(mbedtls_ssl_context *ssl);

void mbedtls_ssl_optimize_checksum(mbedtls_ssl_context *ssl, const mbedtls_ssl_ciphersuite_t *ciphersuite_info);

#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
int mbedtls_ssl_psk_derive_premaster(mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex);
#endif

#if defined(MBEDTLS_PK_C)
unsigned char mbedtls_ssl_sig_from_pk(mbedtls_pk_context *pk);
mbedtls_pk_type_t mbedtls_ssl_pk_alg_from_sig(unsigned char sig);
#endif

mbedtls_md_type_t mbedtls_ssl_md_alg_from_hash(unsigned char hash);
unsigned char mbedtls_ssl_hash_from_md_alg(int md);
int mbedtls_ssl_set_calc_verify_md(mbedtls_ssl_context *ssl, int md);

#if defined(MBEDTLS_ECP_C)
int mbedtls_ssl_check_curve(const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id);
#endif

#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
int mbedtls_ssl_check_sig_hash(const mbedtls_ssl_context *ssl, mbedtls_md_type_t md);
#endif

#if defined(MBEDTLS_X509_CRT_PARSE_C)
static inline mbedtls_pk_context *mbedtls_ssl_own_key(mbedtls_ssl_context *ssl)
{
	mbedtls_ssl_key_cert *key_cert;

	if (ssl->handshake != NULL && ssl->handshake->key_cert != NULL) {
		key_cert = ssl->handshake->key_cert;
	} else {
		key_cert = ssl->conf->key_cert;
	}

	return (key_cert == NULL ? NULL : key_cert->key);
}
static inline mbedtls_x509_crt *mbedtls_ssl_own_cert(mbedtls_ssl_context *ssl)
{
	mbedtls_ssl_key_cert *key_cert;

	if (ssl->handshake != NULL && ssl->handshake->key_cert != NULL) {
		key_cert = ssl->handshake->key_cert;
	} else {
		key_cert = ssl->conf->key_cert;
	}

	return (key_cert == NULL ? NULL : key_cert->cert);
}

/*
 * Check usage of a certificate wrt extensions:
 * keyUsage, extendedKeyUsage (later), and nSCertType (later).
 *
 * Warning: cert_endpoint is the endpoint of the cert (ie, of our peer when we
 * check a cert we received from them)!
 *
 * Return 0 if everything is OK, -1 if not.
 */
int mbedtls_ssl_check_cert_usage(const mbedtls_x509_crt *cert, const mbedtls_ssl_ciphersuite_t *ciphersuite, int cert_endpoint, uint32_t *flags);
#endif							/* MBEDTLS_X509_CRT_PARSE_C */

void mbedtls_ssl_write_version(int major, int minor, int transport, unsigned char ver[2]);
void mbedtls_ssl_read_version(int *major, int *minor, int transport, const unsigned char ver[2]);

static inline size_t mbedtls_ssl_hdr_len(const mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
	if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
		return (13);
	}
#else
	((void)ssl);
#endif
	return (5);
}

static inline size_t mbedtls_ssl_hs_hdr_len(const mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
	if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
		return (12);
	}
#else
	((void)ssl);
#endif
	return (4);
}

#if defined(MBEDTLS_SSL_PROTO_DTLS)
void mbedtls_ssl_send_flight_completed(mbedtls_ssl_context *ssl);
void mbedtls_ssl_recv_flight_completed(mbedtls_ssl_context *ssl);
int mbedtls_ssl_resend(mbedtls_ssl_context *ssl);
#endif

/* Visible for testing purposes only */
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
int mbedtls_ssl_dtls_replay_check(mbedtls_ssl_context *ssl);
void mbedtls_ssl_dtls_replay_update(mbedtls_ssl_context *ssl);
#endif

/* constant-time buffer comparison */
static inline int mbedtls_ssl_safer_memcmp(const void *a, const void *b, size_t n)
{
	size_t i;
	const unsigned char *A = (const unsigned char *)a;
	const unsigned char *B = (const unsigned char *)b;
	unsigned char diff = 0;

	for (i = 0; i < n; i++) {
		diff |= A[i] ^ B[i];
	}

	return (diff);
}

#ifdef __cplusplus
}
#endif

#endif							/* ssl_internal.h */
